unit myAVL;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Buttons, ExtCtrls, StdCtrls;

type
  TVrchol = class
      Info,x,y,Vyvaz,Faza: Integer;
      L, P: TVrchol;
      Bmp: array[0..3] of TBitmap; // obrazky vrcholov
      constructor Create(NoveInfo: integer);
  end;

  AVLStrom = class
  private
    Koren,clicked,Last: TVrchol;
    image: TImage;
    maxX,maxY, priemer,animation,tempx,tempy,speed: integer;
  public
    navrat: array of  integer;
    constructor Create(cc: TImage; width, height: integer);  //vytvorenie AVL stromu
    function Hladaj(X: Integer): TVrchol; // Vyhladanie vrchola s info=X
    function Vloz(X: Integer):boolean;   //Vlozenie noveho vrchola
    function Zrus(typ,X: Integer):boolean; //zrusenie vrchola
    procedure NastavPozicie;   //nastavenie X a Y vrcholom
    function Hlbka(start: TVrchol): Integer;  //hlbka vrcholu start
    procedure kresli;  //vykreslenie stromu
    procedure kresliHranu(); //vykreslenie hran
    function Preorder: string;
    function Inorder: string;
    function Postorder: string;
    procedure dragging(X,Y: Integer;typ: string);  //dragovanie, nie je plne funkcne
    procedure save(del:integer;path: string); //ulozenie stromu
    procedure load(path: string); //nacitanie stromu
    procedure clear; //vycistenie stromu
    procedure Back(what,del:integer);  //krok spat
    procedure Animate(what:string;O:TVrchol);  //animacia
    function Check(O:TVrchol):TVrchol; //kontrola vyvazenosti stromu
    procedure Wait(MilliSec: Integer);  //cakanie
    procedure Posun(V: TVrchol;xx,yy:integer; D: Real); //posuvanie vrcholu
    function setAnimation(a:integer):integer;  //nastavenie animacie
    procedure setAnimationSpeed(a:integer);  //nastavenie rychlosti animacie
  end;


implementation

{TVrchol}

constructor TVrchol.Create(NoveInfo: integer);
var
  b: TBitMap;
  i: integer;
begin
  info:= NoveInfo;
  x:= 0;
  y:= 0;   
  L:= nil;
  P:= nil;
  Vyvaz:= 0;
  Faza:= 0;
  b:= TBitmap.Create;
  b.LoadFromFile('vrcholy/vrcholy.bmp');
  for i:= 0 to 3 do
  begin
    bmp[i]:= TBitmap.Create;
    bmp[i].Width:= b.Width;
    bmp[i].Height:= b.Height div 4;
    bmp[i].PixelFormat:= pf24bit;
    bmp[i].Transparent:= true;
    bmp[i].Canvas.Draw(0, -i*(b.Height div 4), b);
  end;
  b.free; 
end;

{AVLStrom}

constructor AVLStrom.Create(cc: TImage;width, height: integer);
begin
  koren:=nil;
  clicked:= nil;
  image:=cc;
  maxX:= width;
  maxY:= height;
  priemer:=round((maxX-148)/64);
  setlength(navrat,0);
  animation:=1;
  speed:=5;
end;

function AVLStrom.Hlbka(start: TVrchol): Integer;
  function MAX(first,second:integer):integer;     //vyhodnoti 2 cisla
  begin
    if first>second then result:=first else
      result:=second;
  end;
  function Hlbka1(v: TVrchol):integer;
  begin
    if v=nil then result:=0        
    else begin
      result:=Max(Hlbka1(v.L), Hlbka1(v.P)) + 1;
    end;
  end;
begin
  if start=nil then result:=0
  else begin
    result:=Max(Hlbka1(start.L), Hlbka1(start.P)) + 1;
  end;
end;

{///////  Insert, Delete, Rotation  ///////////}

function AVLStrom.Vloz(X: Integer):boolean;

    function Vloz1(O:TVrchol):TVrchol;
    begin
      if O<>nil then begin
        if (X<O.info) AND (O.L<>nil) then
          O.L:=Check(Vloz1(O.L))
        else if (O.L=nil) AND (X<O.info) then
          O.L:=Last
        else if (X>O.info) AND (O.P<>nil) then
          O.P:=Check(Vloz1(O.P))
        else if (X>O.info) AND (O.P=nil) then
          O.P:=Last;
      end;
      result:=O;
    end;

begin
  if(hladaj(X)<>nil) then begin   //ak sa uz nachadza
    result:=false;
  end
  else begin      // vkladat zacneme od korena
    Last:=TVrchol.Create(X);
    if koren=nil then
      koren:=Last
    else
       koren:=Check(Vloz1(Koren));
    result:=true;
    NastavPozicie;
  end;
  kresli;
end;

function AVLStrom.Zrus(typ,X: Integer):boolean;

 function nahradMinZPrava(delete,O:TVrchol):TVrchol;
    function Minimal(V:TVrchol):TVrchol;
    var
      min,pomP: TVrchol;
    begin
      if V.L.L=nil then begin
        min:=V.L;
        pomP:=min.P;
        V.L:=pomP;
        result:=min;
      end else begin
        result:=Minimal(V.L);
        Last:=result;
        if Animation<>-1 then Animate('delete',delete);
        V.L:=Check(V.L);
      end;
    end;
  var
    pom:TVrchol;
  begin
    pom:=delete;
    if O.L=nil then begin
      Last:=O;
      if Animation<>-1 then Animate('delete',delete);
      if pom.P<>O then
        O.P:=pom.P;
      O.L:=pom.L;
      delete:=O;
      result:=delete;
    end else begin
      result:=nahradMinZPrava(delete,Minimal(O));
      result.P:=Check(result.P);
    end;
  end;

  function Zrus2(O:TVrchol):TVrchol;
  begin
    if O<>nil then begin
      if X=O.info then begin
        if O.P<>nil then begin
          O:=nahradMinZPrava(O,O.P);
          O:=Check(O);
        end
        else if O.L<>nil then begin
          Last:=O.L;
          if Animation<>-1 then Animate('delete',O);
          O:=O.L;
          O:=Check(O);
        end else begin
          if Animation<>-1 then Animate('delete',O);
          O:=nil;
        end;
      end else
        if X<O.info then O.L:=Check(Zrus2(O.L))
        else if X>O.info then O.P:=Check(Zrus2(O.P));
    end;
    result:=O;
  end;

  function nahradMaxZLava(delete,O:TVrchol):TVrchol;
    function Maximal(V:TVrchol):TVrchol;
    var
      max,pomL: TVrchol;
    begin
      if V.P.P=nil then begin
        Last:=V.P;
        if Animation<>-1 then Animate('delete',delete);
        max:=V.P;
        pomL:=max.L;
        V.P:=pomL;
        result:=max;
      end else begin
        result:=maximal(V.P);
        V.P:=Check(V.P);
      end;
    end;
  var
    pom:TVrchol;
  begin
    pom:=delete;
    if O.P=nil then begin
      Last:=O;
      if Animation<>-1 then Animate('delete',delete);
      if pom.L<>O then
        O.L:=pom.L;
      O.P:=pom.P;
      delete:=O;
      result:=delete;
    end else begin
      result:=nahradMaxZLava(delete,maximal(O));
      result.L:=Check(result.L);
    end;
  end;

  function Zrus1(O:TVrchol):TVrchol;
  begin
    if O<>nil then begin
      if X=O.info then begin
        if O.L<>nil then begin
          O:=nahradMaxZLava(O,O.L);
          O:=Check(O);
        end
        else if O.P<>nil then begin
          Last:=O.P;
          if Animation<>-1 then Animate('delete',O);
          O:=O.P;
          O:=Check(O);
        end else begin
          if Animation<>-1 then Animate('delete',O);
          O:=nil;
        end;
      end else
        if X<O.info then O.L:=Check(Zrus1(O.L))
        else if X>O.info then O.P:=Check(Zrus1(O.P));
    end;
    result:=O;
  end;

begin
  if(hladaj(X)=nil) then begin
    result:=false;
   end else
  begin
    if koren<>nil then begin
      animation:=-1*animation;
      if typ=1 then begin
        if X=koren.info then begin
          if koren.L<>nil then begin
            koren:=nahradMaxZlava(koren,koren.L);
            koren:=check(koren);
          end
          else if koren.P<>nil then begin
            Last:=koren.P;
            if Animation<>-1 then Animate('delete',koren);
            koren:=koren.P;
            koren:=check(koren);
          end
          else begin
            if Animation<>-1 then Animate('delete',koren);
            koren:=nil;
          end;
        end else
          koren:=Check(Zrus1(Koren));
      end else begin
        if X=koren.info then begin
          if koren.P<>nil then begin
            koren:=nahradMinZPrava(koren,koren.P);
            koren:=check(koren);
          end
          else if koren.L<>nil then begin
            Last:=koren.L;
            if Animation<>-1 then Animate('delete',koren);
            koren:=koren.L;
            koren:=check(koren);
          end
          else begin
            if Animation<>-1 then Animate('delete',koren);
            koren:=nil;
          end;
        end else
          koren:=Check(Zrus2(Koren));
      end;
    end;
    animation:=abs(animation);
    NastavPozicie;
  end;
  kresli;
end;


function AVLStrom.Check(O:TVrchol):TVrchol;

  function simpleRotacia(otec: TVrchol; smer: byte):TVrchol; //jednoducha
  var syn,vnuk,pom: TVrchol;
  begin
    if smer = 0 then // lava-lava rotacia
    begin
      if (Animation>1) then Animate('left-left',otec);
      syn:=otec.L;
      vnuk:=syn.L;
      pom:=otec;
      pom.L:=syn.P;
      syn.P:=pom;
      syn.Vyvaz:=hlbka(syn.P)-hlbka(syn.L);
      syn.L.Vyvaz:=hlbka(syn.L.P)-hlbka(syn.L.L);
      syn.P.Vyvaz:=hlbka(syn.P.P)-hlbka(syn.P.L);
      result:=syn;
    end  else begin // prava-prava rotacia
      if (Animation>1) then Animate('right-right',otec);
      syn:=otec.P;
      vnuk:=syn.P;
      pom:=otec;
      pom.P:=syn.L;
      syn.L:=pom;
      syn.Vyvaz:=hlbka(syn.P)-hlbka(syn.L);
      syn.L.Vyvaz:=hlbka(syn.L.P)-hlbka(syn.L.L);
      syn.P.Vyvaz:=hlbka(syn.P.P)-hlbka(syn.P.L);
      result:=syn;
    end;
  end;

  function doubleRotacia(otec: TVrchol; smer: byte):TVrchol; //zlozita
  var Syn,Vnuk,pom:TVrchol;
  begin
    if smer=0 then begin  //lavo-prava rotacia
      if (Animation>1) then Animate('left-right',otec);
      syn:= otec.L;
      vnuk:= syn.P;
      pom:=syn;
      pom.P:=vnuk.L;
      vnuk.L:=pom;
      otec.L:=vnuk;
      otec:=simpleRotacia(otec,0);
      result:=otec;
    end else begin  //pravo-lava rotacia
      if (Animation>1) then Animate('right-left',otec);
      syn:= otec.P;
      vnuk:= syn.L;
      pom:=syn;
      pom.L:=vnuk.P;
      vnuk.P:=pom;
      otec.P:=vnuk;
      otec:=simpleRotacia(otec,1);
      result:=otec;
    end;
  end;

begin
    if O<>nil then
      O.Vyvaz:=hlbka(O.P)-hlbka(O.L);
      if (Animation>1) then Animate('check',O);
      if (O<>nil) AND ((O.Vyvaz<-1) OR (O.Vyvaz>1)) then begin
        if O.Vyvaz<-1 then begin
          if O.L.Vyvaz<=0 then
            O:=simpleRotacia(O,0)
          else if O.L.Vyvaz>0 then
               O:=doubleRotacia(O,0);
        end
       else
        if O.Vyvaz>1 then begin
          if O.P.Vyvaz>=0 then
            O:=simpleRotacia(O,1)
          else if O.P.Vyvaz<0 then
              O:=doubleRotacia(O,1);
        end;
      end;
      result:=O;
end;

function AVLStrom.Hladaj(X: Integer): TVrchol;
begin
    Result := Koren;
    Last:=TVrchol.Create(X);
    Last.x:=20;
    Last.y:=20;
    Last.faza:=2;
    if Animation<>1 then Animate('compare',Result);
    while (Result <> nil) and (Result.Info <> X) do
      if Result.Info > X then begin
        if Result.L<>nil then
          if Animation<>1 then Animate('compare',Result.L);
        Result := Result.L;
      end
      else begin
        if Result.P<>nil then
          if Animation<>1 then Animate('compare',Result.P);
        Result := Result.P;
      end;
     if Result<>nil then
        Last:=result
     else
       Last:=nil;
    kresli;
    image.Canvas.Font.Size:=20;
    if Last<>nil then begin
      image.Canvas.Font.Color:=clGreen;
      image.Canvas.TextOut(maxX div 2-image.Canvas.TextWidth('Found') div 2,20,'Found');
    end else begin
      image.Canvas.Font.Color:=clRed;
      image.Canvas.TextOut(maxX div 2-image.Canvas.TextWidth('Not found: '+inttostr(X)) div 2,20,'Not found: '+inttostr(X));
    end;
end;

{///////  Paint  ///////////}
procedure AVLStrom.NastavPozicie;

function power(x, y: Integer):Integer;
var i: Integer;
begin
  result:=1;
  for i:=1 to y do
    result:=result*x;
end;

procedure NastavVrchol(v: TVrchol; index: Integer; hlbka: Integer);
var pocet, sirka, dielik, posun: Integer;
begin
      pocet:=power(2, hlbka-1);
      sirka:=round((maxX-20)/pocet);
      dielik:=round((sirka-priemer)/2);
      v.x:=(index-1)*sirka+dielik-10;
      v.y:=hlbka*100-10;
      if v.L <> nil then begin     // ak ma L syna vnori sa f na kreslenie podsynov
        NastavVrchol(v.L, 2*index-1, hlbka+1);
      end;
      if v.P<> nil then begin      // ak ma P syna vnori sa f na kreslenie podsynov
        NastavVrchol(v.P, 2*index, hlbka+1);
      end;
end;

begin
  if koren<>nil then                                           
   NastavVrchol(koren, 1, 1);
end;

procedure AVLStrom.kresli;

  procedure kresli1(v: TVrchol);
  var
    posun, i: Integer;
  begin
      if v=Last then
        V.Faza:=1 else
        V.Faza:=0;
      image.canvas.Draw(v.x,  v.y, v.Bmp[v.Faza]);
      if v.Info div 100 <> 0 then
        posun:=0
      else
        posun:=2;
      image.canvas.Font.Style:= [fsBold];
      if v.Info < 10 then
        i:= 9
      else if v.Info < 100 then
        i:= 6
      else
        i:= 2;
      image.canvas.TextOut(v.x+i, v.y+8, inttostr(v.info));
      image.canvas.Font.Style:= image.canvas.Font.Style-[fsBold];
      image.canvas.TextOut(v.x+15, v.y-15, inttostr(v.Vyvaz));
      if v.L <> nil then    // ak ma L syna vnori sa f na kreslenie podsynov
        kresli1(v.L);
      if v.P<> nil then     // ak ma P syna vnori sa f na kreslenie podsynov
        kresli1(v.P);
  end;

var
  half: integer;
  i: integer;
  pom: TVrchol;
begin
    pom:=koren;
    image.canvas.Brush.Color := clWhite;    //vymazanie plochy
    image.canvas.FillRect(image.canvas.ClipRect);
    image.canvas.Font.Size:=8;
    image.canvas.Font.Color:=clBlack;
    image.canvas.Brush.Style:= bsClear;
    if pom=nil then  begin
          half:= maxX div 2-image.canvas.TextWidth('nil') div 2;
          image.canvas.Font.Size:=10;
          image.canvas.Ellipse(half+5,40,half-25,10);
          image.canvas.TextOut(half-15,20,'nil');
    end else begin
      kresliHranu;
      kresli1(pom);
      if Hlbka(koren)>6 then begin
        image.canvas.Font.Color:=clRed;
        image.Canvas.Font.Size:=20;
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Depth of the tree is too large, may not appear correctly!') div 2,20,'Depth of the tree is too large, may not appear correctly!');
        image.canvas.Font.Color:=clBlack;
      end;
    end;
end;

procedure AVLStrom.kresliHranu();
  procedure kresli1(a,b:TVrchol);
  begin
    image.canvas.Pen.Width:= 2;
    image.canvas.Pen.Color:= clGray;
    image.Canvas.MoveTo(a.X+15,a.Y+15);
    image.Canvas.LineTo(b.X+15,b.Y+15);
    if b.L<>nil then begin
      kresli1(b,b.L);
    end;
    if b.P<>nil then begin
      kresli1(b,b.P);
    end;
  end;

var
  start: TVrchol;
begin
  start:= koren;
  if start.L<>nil then begin
    kresli1(start,start.L);
  end;
  if start.P<>nil then begin
    kresli1(start,start.P);
  end;
end;

{///////  Orders  ///////////}
function AVLStrom.Preorder: string;
  function Preorder1(v :TVrchol): string;
  begin
    Result:='';
    Result:=Result+inttostr(v.info)+' ';
    if (v.L<>nil) then
      Result:=Result+Preorder1(v.L)+' ';
    if(v.P<>nil) then
      Result:=Result+Preorder1(v.P)+' ';
  end;

var
  start: TVrchol;
begin
  start:= koren;
  Result:='';
  if start<>nil then begin
    Result:=Result+inttostr(start.info)+' ';
    if (start.L<>nil) then
      Result:=Result+Preorder1(start.L)+' ';
    if(start.P<>nil) then
      Result:=Result+Preorder1(start.P)+' ';
  end;
end;

function AVLStrom.Inorder: string;
  function Inorder1(v :TVrchol): string;
  begin
    Result:='';
    if (v.L<>nil)then
      Result:=Result+Inorder1(v.L)+' ';
    Result:=Result+inttostr(v.info)+' ';
    if(v.P<>nil) then
      Result:=Result+Inorder1(v.P)+' ';
  end;
var
  start: TVrchol;
begin
  start:= koren;
  Result:='';
  if start<>nil then begin
    if (start.L<>nil)then
      Result:=Result+Inorder1(start.L)+' ';
    Result:=Result+inttostr(start.info)+' ';
    if(start.P<>nil) then
      Result:=Result+Inorder1(start.P)+' ';
  end;
end;

function AVLStrom.Postorder: string;
  function Postorder1(v :TVrchol): string;
  begin
    Result:='';
    if (v.L<>nil) then
      Result:=Result+Postorder1(v.L)+' ';
    if(v.P<>nil) then
      Result:=Result+Postorder1(v.P)+' ';
    Result:=Result+inttostr(v.info)+' ';
  end;
var
  start: TVrchol;
begin
  start:= koren;
  Result:='';
  if start<>nil then begin
    if (start.L<>nil) then
      Result:=Result+Postorder1(start.L)+' ';
    if(start.P<>nil) then
      Result:=Result+Postorder1(start.P)+' ';
    Result:=Result+inttostr(start.info)+' ';
  end;
end;

{///////  Dragging  ///////////}
procedure AVLStrom.dragging(X,Y: Integer; typ: string);
var
  start: TVrchol;
  i: integer;
begin
    start:=koren;
    if typ='click' then begin
      if start<>nil then begin            
        while (Sqrt(Sqr(start.X - X) + Sqr(start.Y - Y)) > 30) do  begin
          if (start.x > X) then begin
            start := start.L;
            if start=nil then break;
          end else
          if (start.x < X) then begin
            start := start.P;
            if start=nil then break;
          end;
        end;
        if start<>nil then begin
          clicked:=start;
          Last:=clicked;
          tempx:=clicked.x;
          tempy:=clicked.y;
          kresli;
          image.Canvas.Font.Size:=10;
          image.Canvas.Font.Color:=clBlack;
          image.Canvas.Brush.Color:=clYellow;
          image.Canvas.TextOut(10,10,inttostr(start.Info)+'-> X:'+inttostr(clicked.X)+' Y:'+inttostr(clicked.Y));
        end else clicked:=nil;
      end;
    end;
    if typ='drag' then
      if clicked<>nil then begin
        clicked.y:= Y;
        clicked.x:= X;
        kresli;
        image.Canvas.Font.Size:=10;
        image.Canvas.Font.Color:=clWhite;
        image.Canvas.Brush.Color:=clBlack;
        image.Canvas.TextOut(10,10,inttostr(clicked.Info)+'-> X:'+inttostr(clicked.X)+' Y:'+inttostr(clicked.Y));
      end;
    if typ='stop' then begin
      if clicked<>nil then begin
        while Sqrt(Sqr(tempx-clicked.x)+Sqr(tempy-clicked.y)) > 5 do begin
          kresli;
          if clicked.Info < 10 then  i:= 9
            else if clicked.Info < 100 then  i:= 6
              else i:= 2;
          image.canvas.Font.Style:= [fsBold];
          image.Canvas.Draw(clicked.x,clicked.y, clicked.Bmp[clicked.Faza]);
          image.canvas.TextOut(clicked.x+i, clicked.y+8, inttostr(clicked.info));
          posun(clicked,tempx,tempy,5);
          wait(5);
        end;
        clicked:= nil;
      end;
    end;
end;
{///////  Save & load  ///////////}
procedure AVLStrom.save(del:integer;path:string);
var
  f: TFileStream;
  i: integer;

begin
  if length(navrat)>0 then begin
    if FileExists(path) then deletefile(path);
    f:= TFileStream.Create(path,fmCreate);
    f.Write(del, sizeOf(integer));
    for I := 0 to high(navrat) do
      f.Write(navrat[i], sizeOf(integer));  // zapiseme info
    image.Canvas.Font.Size:=10;
    image.Canvas.Font.Color:=clWhite;
    image.Canvas.Brush.Color:=clGreen;
    image.Canvas.TextOut(10,10,'Tree saved');
    f.Free;
  end;
end;

procedure AVLStrom.load(path: string);
var
  vrchol,del,x,y,l,p: integer;
  a,b: Byte;
  f: TFileStream;
begin
    if FileExists(path) then  begin
      clear;
      setlength(navrat,0);
      f:= TFileStream.Create(path,fmOpenRead);
      F.Read(del, SizeOf(integer));
      while F.Position < F.Size do
      begin
        F.Read(vrchol, SizeOf(integer));
        if vrchol>0 then
          Vloz(vrchol)
        else      
          Zrus(del,-1*vrchol);
        setlength(navrat,length(navrat)+1);
        navrat[high(navrat)]:=vrchol;
      end;
      kresli;
      image.Canvas.Font.Size:=10;
      image.Canvas.Font.Color:=clWhite;
      image.Canvas.Brush.Color:=clGreen;
      image.Canvas.TextOut(10,10,'Tree loaded');
      f.free;
    end;
end;

{///////  Clear  ///////////}
procedure AVLStrom.clear;
  procedure delete(v: TVrchol);
  begin
    if v.L<>nil then begin
      delete(v.L);
      v.L:=nil;
      v.L.Free;
    end;
    if v.P<>nil then begin
      delete(v.P);
      v.P:=nil;
      v.P.Free;
    end;
    v:=nil;
  end;

begin
  if koren<>nil then
  begin
    if koren.L<>nil then begin
      delete(koren.L);
      koren.L:=nil;
      koren.L.Free;
    end;
    if koren.P<>nil then begin
      delete(koren.P);
      koren.P:=nil;
      koren.P.Free;
    end;
    koren:=nil;
   Last:=nil;
   Clicked:=nil;
   kresli;
  end;
end;

{///////  Back  ///////////}
procedure AVLStrom.Back(what,del:integer);
var
  i,max: integer;
begin
  if what<>0 then begin
    setlength(navrat,length(navrat)+1);
    navrat[high(navrat)]:=what;
  end else begin
    if length(navrat)>0 then begin
      clear;
      setlength(navrat,length(navrat)-1);
      for i := 0 to high(navrat) do
        if navrat[i]>0 then
          Vloz(navrat[i])
        else
          Zrus(del,-1*navrat[i]);
    end else
      clear;
  end;
end;

{///////  Animation  ///////////}
procedure AVLStrom.Wait(MilliSec: Integer);
begin
  if Image <> nil then
    Image.Repaint;
  Sleep(MilliSec);
end;

procedure AVLStrom.Posun(V:TVrchol;xx,yy:integer; D: Real); // V-co, xx,yy-kam, D-o kolko
  function NastavUhol(V: TVrchol;xx,yy:integer):Real;
  var
    Angle, X, Y: Real;
  begin
    X:= xx - V.x;
    Y:= V.y - yy;
    if Y = 0 then
      if X = 0 then
        Angle := 0
      else if X < 0 then
        Angle := 270
      else
        Angle := 90
    else if Y > 0 then
      if X >= 0 then
        Angle := ArcTan(X/Y)*(180/Pi)
      else
        Angle := 360 - ArcTan(-X/Y)*(180/Pi)
    else if X >= 0 then
      Angle := 180 - ArcTan(-X/Y)*(180/Pi)
    else
      Angle := 180 + ArcTan(X/Y)*(180/Pi);
    while Angle < 0 do
      Angle:= Angle + 360;
    while Angle >= 360 do
      Angle:= Angle - 360;
    Result:= Angle;
  end;
var
  Uhol: Real;
begin
  Uhol:= NastavUhol(V, xx,yy);
  V.x:= Round(V.x + Sin(Uhol*(Pi/180))*D);
  V.y:= Round(V.y - Cos(Uhol*(Pi/180))*D);
end;

procedure AVLStrom.Animate(what:string;O:TVrchol);
var
  i,pomx1,pomy1,pomx2,pomy2: integer;
  text: string;
  pom1,pom2,pom3: TVrchol;
begin
  image.Canvas.Font.Size:=8;
  image.canvas.Font.Style:= [fsBold];
    if Last.Info < 10 then  i:= 9
    else if Last.Info < 100 then  i:= 6
      else  i:= 2;
  if (what='left-left') OR (what='right-right') then begin //animacia pre rotaciu
    nastavpozicie;
    pomx1:=O.x;
    pomy1:=O.y;
    pom1:=TVrchol.Create(O.Info);
    pom1.x:=O.x;
    pom1.y:=O.y;
    if (what='left-left') then begin
      pomx2:=O.L.x;
      pomy2:=O.L.y;
      pom2:=TVrchol.Create(O.L.Info);
      pom2.x:=O.L.x;
      pom2.y:=O.L.y;
      pom3:=TVrchol.Create(O.L.L.Info);
      pom3.x:=O.L.L.x;
      pom3.y:=O.L.L.y;
      pom1.L:=pom2;
      pom2.L:=pom3;
    end else begin
      pomx2:=O.P.x;
      pomy2:=O.P.y;
      pom2:=TVrchol.Create(O.P.Info);
      pom2.x:=O.P.x;
      pom2.y:=O.P.y;
      pom3:=TVrchol.Create(O.P.P.Info);
      pom3.x:=O.P.P.x;
      pom3.y:=O.P.P.y;
      pom1.P:=pom2;
      pom2.P:=pom3;
    end;
    if Animation=2 then begin
      kresli;
      image.Canvas.Font.Size:=20;
      image.Canvas.Font.Color:=clGreen;
      if (what='left-left') then
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Left-left rotation') div 2,20,'Left-left rotation')
      else
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Right-right rotation') div 2,20,'Right-right rotation');
      wait(1000);
    end;
    if Animation=3 then begin
      while Sqrt(Sqr(pomx1-pom2.x)+Sqr(pomy1-pom2.y)) > 5 do begin
        kresli;
        pom1.Faza:=2;
        pom2.Faza:=2;
        pom3.Faza:=2;
        image.canvas.Pen.Width:= 2;
        image.canvas.Pen.Color:= clGray;
        image.Canvas.MoveTo(pom1.X+15,pom1.Y+15);
        image.Canvas.LineTo(pom2.X+15,pom2.Y+15);
        image.Canvas.MoveTo(pom2.X+15,pom2.Y+15);
        image.Canvas.LineTo(pom3.X+15,pom3.Y+15);
        image.canvas.Font.Style:= [fsBold];
        image.Canvas.Draw(pom1.x,pom1.y, pom1.Bmp[pom1.Faza]);
        image.canvas.TextOut(pom1.x+i, pom1.y+8, inttostr(pom1.info));
        image.Canvas.Draw(pom2.x,pom2.y, pom2.Bmp[pom2.Faza]);
        image.canvas.TextOut(pom2.x+i, pom2.y+8, inttostr(pom2.info));
        image.Canvas.Draw(pom3.x,pom3.y, pom3.Bmp[pom3.Faza]);
        image.canvas.TextOut(pom3.x+i, pom3.y+8, inttostr(pom3.info));
        image.canvas.Font.Style:= image.canvas.Font.Style-[fsBold];
        posun(pom1,pomx1+(pomx1-pomx2),pomy2,speed);
        posun(pom2,pomx1,pomy1,speed);
        posun(pom3,pomx2,pomy2,speed);
        image.Canvas.Font.Size:=20;
        image.Canvas.Font.Color:=clGreen;
        image.canvas.Font.Style:= image.canvas.Font.Style-[fsBold];
        if (what='left-left') then
          image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Left-left rotation') div 2,20,'Left-left rotation')
        else
          image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Right-right rotation') div 2,20,'Right-right rotation');
        wait(5);
      end;
    end;
  end;
  if (what='right-left') OR (what='left-right') then begin //animacia pre rotaciu
    nastavpozicie;
    if (what='right-left') then begin
      pomx1:=O.x+((O.P.x-O.x) div 2);
      pomy1:=O.y+((O.P.y-O.y) div 2);
      pom1:=TVrchol.Create(O.P.L.Info);
      pom1.x:=O.P.L.x;
      pom1.y:=O.P.L.y;
      pom2:=TVrchol.Create(O.P.Info);
      pom2.x:=O.P.x;
      pom2.y:=O.P.y;
    end else begin
      pomx1:=O.x-((O.x-O.L.x) div 2);
      pomy1:=O.y+((O.L.y-O.y) div 2);
      pom1:=TVrchol.Create(O.L.P.Info);
      pom1.x:=O.L.P.x;
      pom1.y:=O.L.P.y;
      pom2:=TVrchol.Create(O.L.Info);
      pom2.x:=O.L.x;
      pom2.y:=O.L.y;
    end;
    if Animation=2 then begin
      kresli;
      image.Canvas.Font.Size:=20;
      image.Canvas.Font.Color:=clGreen;
      if (what='right-left') then
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Right-left rotation') div 2,20,'Right-left rotation')
      else
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Left-right rotation') div 2,20,'Left-right rotation');
      wait(1000);
    end;
    if Animation=3 then begin
      while Sqrt(Sqr(pomx1-pom1.x)+Sqr(pomy1-pom1.y)) > 5 do begin
        kresli;
        pom1.Faza:=2;
        pom2.Faza:=2;
        image.canvas.Pen.Width:= 2;
        image.canvas.Pen.Color:= clGray;
        image.Canvas.MoveTo(pom1.X+15,pom1.Y+15);
        image.Canvas.LineTo(pom2.X+15,pom2.Y+15);
        image.canvas.Font.Style:= [fsBold];
        image.Canvas.Draw(pom1.x,pom1.y, pom1.Bmp[pom1.Faza]);
        image.canvas.TextOut(pom1.x+i, pom1.y+8, inttostr(pom1.info));
        image.Canvas.Draw(pom2.x,pom2.y, pom2.Bmp[pom2.Faza]);
        image.canvas.TextOut(pom2.x+i, pom2.y+8, inttostr(pom2.info));
        posun(pom1,pomx1,pomy1,speed);
        image.Canvas.Font.Size:=20;
        image.Canvas.Font.Color:=clGreen;
        image.canvas.Font.Style:= image.canvas.Font.Style-[fsBold];
        if (what='right-left') then
          image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Right-left rotation') div 2,20,'Right-left rotation')
        else
          image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Left-right rotation') div 2,20,'Left-right rotation');
        wait(5);
      end;
    end;
  end;
  if what='compare' then begin //animacia pre porovnavanie
    if O<>nil then begin
      if Animation=2 then begin
        kresli;
        Last.X:=O.x;
        Last.Y:=O.y;
        image.canvas.Font.Style:= [fsBold];
        image.Canvas.Draw(last.x,last.y, last.Bmp[last.Faza]);
        image.canvas.TextOut(Last.x+i, Last.y+8, inttostr(Last.info));
        image.canvas.Font.Style:= image.canvas.Font.Style-[fsBold];
        wait(1000-speed);
      end;
      if Animation=3 then begin
        while Sqrt(Sqr(O.x-last.x)+Sqr(O.y-last.y)) > 5 do begin
          kresli;
          image.canvas.Font.Style:= [fsBold];
          image.Canvas.Draw(last.x,last.y, last.Bmp[last.Faza]);
          image.canvas.TextOut(Last.x+i, Last.y+8, inttostr(Last.info));
          image.canvas.Font.Style:= image.canvas.Font.Style-[fsBold];
          posun(Last,O.x,O.y,speed);
          wait(5);
        end;
      end;
      image.Canvas.Font.Size:=20;
      image.Canvas.Font.Color:=clGreen;
      if O.Info=Last.info then
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('=') div 2,20,'=');
      image.Canvas.Font.Color:=clRed;
      if O.Info<Last.info then begin
        text:='>';
        if O.P=nil then text:=text+' NIL';
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth(text) div 2,20,text);
      end else
      if O.Info>Last.info then begin
        text:='<';
        if O.L=nil then text:=text+' NIL';
        image.canvas.TextOut(maxX div 2-image.canvas.TextWidth(text) div 2,20,text);
      end;
      wait(1000-speed);
    end;
  end;
  if what='check' then begin //animacia pre check
    nastavpozicie;
    kresli;
    if O<>nil then begin
      if (O.Vyvaz<-1) OR (O.Vyvaz>1) then begin
        image.Canvas.Font.Color:=clRed;
        image.Canvas.Font.Size:=20;
        image.Canvas.TextOut(O.x+priemer+25,O.y,'BAD');
      end else begin
        image.Canvas.Font.Color:=clGreen;
        image.Canvas.Font.Size:=20;
        image.Canvas.TextOut(O.x+priemer+25,O.y,'OK');
      end;
      wait(1000-speed);
    end;
  end;
  if what='delete' then begin //animacia pre delete
    kresli;
    image.canvas.Font.Style:= [fsBold];
    image.Canvas.Draw(last.x,last.y, last.Bmp[last.Faza]);
    image.canvas.TextOut(Last.x+i, Last.y+8, inttostr(Last.info));
    O.faza:=3;
    image.Canvas.Draw(O.x,O.y, O.Bmp[O.Faza]);
    image.canvas.TextOut(O.x+3, O.y+8, inttostr(O.info));
    image.Canvas.Font.Color:=clGreen;
    image.Canvas.Font.Size:=20;
    image.canvas.TextOut(maxX div 2-image.canvas.TextWidth('Delete: '+inttostr(O.info)) div 2,20,'Delete: '+inttostr(O.info));
    wait(1000-speed);
  end;
end;


function AVLStrom.setAnimation(a:integer):integer;
begin
  result:=animation;
  animation:=a;
end;

procedure AVLStrom.setAnimationSpeed(a:integer);
begin
  speed:=a;
end;

end.
